home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / COMMUNIC / 1572C.ZIP / KMT_IBM_.ZIP / MSSRCV.ASM
Assembly Source File  |  1989-07-11  |  52KB  |  1,016 lines

  1.         NAME    mssrcv
  2. ; File MSSRCV.ASM
  3. ; Edit history
  4. ; Last edit 24 Nov 1988
  5. ; 24 Nov 1988 Add 100% screen msg done upon successful file reception.
  6. ; 21 Nov 1988 Version 2.32
  7. ; 12 Nov 1988 Modify disk space arithmetic for DOS 4 # sectors > 64K.
  8. ; 4 Aug 1988 Correct filesize test for attributes packets. Let ioctl tell
  9. ;  us the block device ident (for bridged or joined drives), from Henrik
  10. ;  Levokwetz.
  11. ; 1 July 1988 Version 2.31
  12. ; 12 June 1988 Add error recovery if serial port does not initialize.
  13. ; 31 May 1988 Use proc spchk to check available disk space
  14. ;  when using file attributes.
  15. ; 15 May 1988 Add kstatus global status word
  16. ; 23 Feb 1988 Add Mail command. [jrd]
  17. ; 14 Feb 1988 Add Attributes packets. [jrd]
  18. ; 27 Jan 1988 Remove serrst call, done now in mssker idle loop. [jrd]
  19. ; 7 Jan 1988 Check for Control-E condition before sending a NAK. [jrd]
  20. ; 1 Jan 1988 version 2.30
  21. ; 26 Dec 1987 Clean out unused pack.oldtry, etc., clean up. [jrd]
  22. ; 6 Dec 1987 Flush last disk buffer when aborting a transfer. [jrd]
  23. ; 8 Oct 1987 Ensure error pkts use 1 byte chksum at init stage. [jrd]
  24. ; 27 Aug 1987 Add tests for receiving to screen for error reports [jrd]
  25. ; 23 July 1987 Add buffer clear after opening new output file. [jrd]
  26. ; 7 June 1987 Add DOS errlev return of 2 for failure to receive. [jrd]
  27. ; 7 May 1987 Correct placement of begtim and endtim statistics calls. [jrd]
  28. ; 19 Oct 1986 Fix Rinit to use 1 byte checksums on Naks to S packets.
  29. ; 1 Oct 1986 Version 2.29a
  30. ; 17 Sept 1986 Fix file not being deleted when transfer fails. [jrd]
  31. ; 14 August 1986 Allow changing EOL characters.
  32. ; 9 August 1986 Allow Control-X/Z exit while getting 'S' packet. [jrd]
  33. ; 27 July 1986 Clear file opened flag to prevent unwanted closing of stdin.
  34. ; 16 June 1986 Add clearing of "flags.getflg" under read0: to prevent missing
  35. ;  initial packet read for REC commands. [jrd]
  36. ; 26 May 1986 Revise code to permit serial display. [jrd]
  37. ; [2.29] code frozen on 6 May 1986 [jrd]
  38.  
  39.         public  read12, read2, rin21, rfile3, read, updrtr, nak, rrinit
  40.         include mssdef.h
  41.  
  42. datas   segment public 'datas'
  43.         extrn   data:byte, bufpnt:word, chrcnt:word, curchk:byte, fmtdsp:byte
  44.         extrn   flags:byte, pack:byte, trans:byte, dtrans:byte
  45.         extrn   diskio:byte, locfil:byte, maxtry:byte, imxtry:byte
  46.         extrn   fsta:word, errlev:byte, ofilsz:word, kstatus:word
  47.  
  48. setattr equ     57h                     ; DOS get/set file's date and time
  49.  
  50. ermes7  db      '?Unable to receive initiate-packet$'
  51. ermes8  db      '?Unable to receive file name$'
  52. ermes9  db      '?Unable to receive end of file$'
  53. erms10  db      '?Unable to receive data$'
  54. erms11  db      'Not enough disk space for file$'
  55. infms1  db      cr,'           Receiving: In progress',cr,lf,'$'
  56. infms3  db      'Completed',cr,lf,'$'
  57. infms4  db      'Failed',cr,lf,'$'
  58. infms6  db      'Interrupted',cr,lf,'$'
  59. donemsg db      '100%$'
  60. filhlp2 db      ' Local path or filename or carriage return$'
  61. ender   db      bell,bell,'$'
  62. crlf    db      cr,lf,'$'
  63. temp    dw      0
  64. filopn  db      0               ; Says if disk file is open
  65. ftime   db      0,0             ; file time (defaults to 00:00:00)
  66. fdate   db      0,0             ; file date (defaults to 1 Jan 1980)
  67. attrib  db      0               ; attribute code causing file rejection
  68. datas   ends
  69.  
  70. code    segment public 'code'
  71.         extrn   gofil:near, outbuf:near, comnd:near
  72.         extrn   spack:near, rpack:near, serini:near, serrst:near
  73.         extrn   spar:near, rpar:near, init:near, cxmsg:near, perpos:near
  74.         extrn   error:near, error1:near, ptchr:near, erpos:near, rtpos:near
  75.         extrn   stpos:near, rprpos:near, nppos:near, nout:near
  76.         extrn   dodec:near, doenc:near, errpack:near, intmsg:near
  77.         extrn   send11:near, clrmod:near, ihostr:near
  78.         extrn   begtim:near, endtim:near, pktsize:near,strlen:near,strcpy:near
  79.         assume  cs:code, ds:datas
  80.  
  81. ; Update retry count and fall through to send a NAK
  82.  
  83. NAK0:   call    updrtr                  ; Update retry count
  84. nak1:   cmp     flags.cxzflg,'E'        ; Protocol abort sign?
  85.         jne     nak2                    ; ne = no
  86.         ret                             ; return to do current ('A') state
  87. nak2:   cmp     flags.cxzflg,'C'        ; Control-C abort?
  88.         jne     nak                     ; ne = no
  89.         mov     pack.state,'A'          ; set Abort state
  90.         ret
  91.  
  92. NAK:    mov     ax,pack.pktnum       ; Get the packet number we're waiting for
  93.         mov     pack.seqnum,ax
  94.         mov     pack.datlen,0           ; no data
  95.         add     fsta.nakscnt,1          ; count NAKs sent
  96.         mov     ah,'N'                  ; NAK that packet
  97.         call    spack
  98.          jmp    abort                   ; failed
  99.          nop
  100.         ret
  101.  
  102. updrtr: cmp     pack.state,'A'          ; Supposed to abort?
  103.         je      upd0                    ; Yes, don't bother with retry count
  104.         inc     pack.numrtr             ; Increment the number of retries
  105.         cmp     flags.xflg,1            ; Writing to screen?
  106.         je      upd0                    ; e = yes, skip this
  107.         cmp     pack.numrtr,0           ; non-zero item to display?
  108.         je      upd0                    ; nothing to display
  109.         push    ax                      ; save packet type in ah
  110.         call    rtpos                   ; Position cursor
  111.         mov     ax,pack.numrtr
  112.         call    nout                    ; Write the number of retries
  113.         pop     ax                      ; recover packet type in ah
  114. upd0:   ret
  115.  
  116. ;       Abort
  117. ABORT   PROC    NEAR
  118.         cmp     filopn,0                ; Disk file open?
  119.         je      abort0                  ; e = no so don't close
  120.         cmp     flags.xflg,1            ; Writing to the screen?
  121.         je      abort0                  ; Yes, don't close "file"
  122.         call    outbuf          ; flush last buffer to disk, ignore errors
  123.          nop
  124.          nop
  125.          nop
  126.         mov     ah,close2               ; DOS 2.0 file close
  127.         push    bx
  128.         mov     bx,diskio.handle        ; file handle
  129.         int     dos
  130.         pop     bx
  131.         mov     filopn,0                ; say file is no longer open
  132.         cmp     flags.abfflg,0          ; save file after closing?
  133.         je      abort0                  ; e = yes
  134.         push    dx
  135.         mov     dx,offset diskio.string ; get back file name
  136.         mov     ah,del2                 ; delete the file
  137.         int     dos
  138.         pop     dx
  139. abort0: mov     pack.state,'A'          ; Otherwise abort
  140.         mov     byte ptr locfil,0       ; clear local filename
  141.         or      errlev,2                ; set DOS error level
  142.         or      fsta.xstatus,2          ; set status
  143.         mov     kstatus,2               ; global status
  144.         xor     ax,ax           ; tell statistics this is a receive operation
  145.         call    endtim                  ; stop file timer
  146.         ret
  147. ABORT   ENDP
  148.  
  149. ackpak  proc    near                    ; send an ACK packet
  150.         mov     ah,'Y'                  ; ack packet
  151.         call    spack
  152.          jmp    abort                   ; failed
  153.          nop
  154.         ret
  155. ackpak  endp
  156.  
  157. ; init variables for read...
  158. rrinit  proc    near
  159.         mov     pack.numpkt,0           ; Set the number of packets to zero
  160.         mov     pack.numrtr,0           ; Set the number of retries to zero
  161.         mov     pack.pktnum,0           ; Set the packet number to zero
  162.         mov     pack.numtry,0           ; Set the number of tries to zero
  163.         mov     filopn,0                ; say no file opened yet
  164.         ret
  165. rrinit  endp
  166.  
  167. ;       RECEIVE command  --  Some code moved to the GET routine
  168.  
  169. READ    PROC    NEAR
  170.         mov     flags.nmoflg,0          ; Override file name from other host
  171.         mov     bx,offset filhlp2       ; Text of help message
  172.         mov     dx,offset locfil        ; local file name string
  173.         mov     byte ptr locfil,0       ; clear it first
  174.         mov     ah,cmfile               ; allow path names
  175.         call    comnd
  176.          ret
  177.          nop
  178.          nop
  179.         cmp     ah,0                    ; was an override filename given?
  180.         je      read0                   ; e = no
  181.         mov     flags.nmoflg,1          ; yes, set flag = use this filename
  182. read0:  mov     ah,cmcfm                ; Get a confirm
  183.         call    comnd
  184.          ret
  185.          nop
  186.          nop
  187.         mov     pack.state,'R'  ; Set the state to receive initiate
  188.         mov     flags.getflg,0          ; Reset flag (not a Get command)
  189.         mov     flags.xflg,0
  190.         call    serini                  ; initialize serial port
  191.         jnc     read0b                  ; nc = success
  192.         or      errlev,2                ; set DOS error level
  193.         or      fsta.xstatus,2          ; set status, failed
  194.         or      kstatus,2               ; global status
  195.         test    flags.remflg,dquiet     ; quiet display mode?
  196.         jnz     read0a                  ; nz = yes. Don't write to screen
  197.         mov     ah,prstr
  198.         mov     dx,offset infms4        ; Failed message
  199.         int     dos
  200. read0a: ret                             ; return failure
  201. read0b: call    rrinit                  ; init variables for read
  202.         call    init                    ; setup display form
  203.         call    ihostr                  ; initialize the host
  204.  
  205. READ12:                                 ; Called by GET & SRVSND, display ok
  206.         mov     kstatus,0               ; global status, success
  207.         call    begtim                  ; start next statistics group
  208.         mov     flags.cxzflg,0          ; Reset ^X/^Z flag
  209.         mov     ah,trans.chklen         ; get desired checksum length
  210.         mov     curchk,ah               ; and remember it here
  211.         test    flags.remflg,dquiet     ; quiet display mode?
  212.         jnz     read2                   ; nz = yes, no printing
  213.         cmp     flags.destflg,2         ; Receiving to the screen?
  214.         je      read21                  ; e = yes, no formatted display
  215.         call    stpos
  216.         mov     ah,prstr                ; Be informative
  217.         mov     dx,offset infms1
  218.         int     dos
  219.         test    flags.remflg,dserial    ; serial display mode?
  220.         jnz     read2                   ; nz = yes, skip initial retry display
  221.         call    rtpos                   ; Position cursor
  222.         mov     ax,pack.numrtr
  223.         call    nout                    ; Write the number of retries
  224.  
  225. READ2:                          ; Called by GENERIC server command dispatcher
  226.         cmp     flags.xflg,1            ; Are we receiving to the screen?
  227.         je      read21                  ; e = skip the screen stuff
  228.         call    nppos            ; Position cursor for number of packets msg
  229.         mov     ax,pack.numpkt
  230.         call    nout                    ; Write the number of packets
  231. read21: mov     ah,pack.state           ; Get the state
  232.         cmp     ah,'D'                  ; Data receive state?
  233.         jne     read3
  234.         call    rdata                   ; yes, get data packets
  235.         jmp     read2
  236. read3:  cmp     ah,'F'                  ; File receive state?
  237.         jne     read4
  238.         call    rfile                   ; Call receive file
  239.         jmp     read2
  240. read4:  cmp     ah,'R'                  ; Receive initiate state?
  241.         jne     read5                   ; ne = no
  242.         call    rinit
  243.         jmp     read2
  244.                                         ; Receive Complete state processor
  245. read5:  push    ax                      ; save status in ah
  246.         cmp     flags.cxzflg,0          ; Completed or interrupted?
  247.         je      read5a                  ; e = ended normally
  248.         or      errlev,2                ; set DOS error level
  249.         or      fsta.xstatus,2+80h      ; set status, failed + intervention
  250.         or      kstatus,2+80h           ; global status
  251. read5a: push    ax
  252.         xor     ax,ax           ; tell statistics this is a receive operation
  253.         call    endtim                  ; stop file timer
  254.         pop     ax
  255.         mov     ah,curchk               ; get working checksum
  256.         mov     trans.chklen,ah         ; and restore for next file
  257.         mov     byte ptr locfil,0       ; clear local filename
  258.         pop     ax                      ; recover status in ah
  259.         mov     dx,offset infms3        ; Completed message
  260.         cmp     ah,'C'                  ; Receive complete state?
  261.         je      read6                   ; e = yes, else receive failed
  262.         or      errlev,2                ; set DOS error level
  263.         or      fsta.xstatus,2          ; set status, failed
  264.         or      kstatus,2               ; global status
  265.         mov     dx,offset infms4        ; Failed message
  266.         cmp     filopn,2                ; file still open?
  267.         jne     read6                   ; ne = no
  268.         push    dx
  269.         call    abort                   ; close file & maybe delete
  270.         pop     dx
  271. read6:  cmp     flags.xflg,0            ; Did we write to the screen?
  272.         je      read6a                  ; e = no, so print status
  273.         cmp     flags.destflg,2         ; Receiving to screen?
  274.         je      read6d                  ; Yes don't reset
  275.         mov     flags.xflg,0            ; Reset it
  276.         jmp     read6d                  ; Yes, so just return
  277. read6a: test    flags.remflg,dquiet     ; quiet display mode?
  278.         jnz     read6d                  ; nz = yes, keep going
  279.         cmp     flags.destflg,2         ; Receiving to the screen?
  280.         je      read6d                  ; e = yes, no formatted display
  281.         push    dx                      ; save message pointer
  282.         call    stpos                   ; Position cursor
  283.         pop     dx
  284.         mov     ah,prstr
  285.         cmp     flags.cxzflg,0          ; Completed or interrupted?
  286.         je      read6b                  ; Ended normally
  287.         mov     dx,offset infms6        ; Say was interrupted
  288. read6b: int     dos
  289.         cmp     flags.belflg,0          ; Bell desired?
  290.         je      read6c                  ; No
  291.         mov     dx,offset ender         ; Ring them bells
  292.         int     dos
  293. read6c: test    flags.remflg,dserial    ; serial display?
  294.         jnz     read6d                  ; nz = yes
  295.         call    clrmod                  ; clear Mode Line
  296.         call    rprpos                  ; Put prompt here
  297. read6d: jmp     rskp
  298. READ    ENDP
  299.  
  300. ;       Receive routines
  301.  
  302. ;       Receive init
  303. RINIT   PROC    NEAR
  304.         mov     ah,pack.numtry          ; Get the number of tries
  305.         cmp     ah,imxtry               ; Reached the maximum number of tries?
  306.         jl      rinit2
  307.         mov     dx,offset ermes7
  308.         test    flags.remflg,dquiet     ; quiet display mode?
  309.         jnz     rinit1                  ; nz = yes. Don't write to screen
  310.         cmp     flags.destflg,2         ; Receiving to the screen?
  311.         je      rinit1                  ; e = yes, no formatted display
  312.         call    erpos                   ; Position cursor
  313.         mov     ah,prstr
  314.         int     dos                     ; Print an error message
  315. rinit1: mov     bx,dx
  316.         mov     ah,trans.chklen
  317.         mov     curchk,ah               ; Store checksum length we want to use
  318.         mov     trans.chklen,1          ; Send init checksum is always 1 char
  319.         call    errpack                 ; Send error packet just in case
  320.         mov     ah,curchk
  321.         mov     trans.chklen,ah         ; Reset to desired value
  322.         jmp     abort                   ; Change the state to abort
  323. rinit2: inc     ah                      ; Increment it
  324.         mov     pack.numtry,ah          ; Save the updated number of tries
  325.         mov     ah,flags.getflg         ; Get cmd? (holds get pkt type in ah)
  326.         cmp     ah,0                    ; Have we already read in the packet?
  327.         jne     rin21a                  ; ne = yes, so don't call RPACK
  328.         mov     ah,dtrans.seol          ; restore default end-of-line char
  329.         mov     trans.seol,ah
  330.         mov     ah,trans.chklen
  331.         mov     curchk,ah               ; Save checksum length we want to use
  332.         mov     trans.chklen,1          ; Use 1 char for init packet
  333.         call    rpack                   ; Get a packet
  334.          jmp    rin22                   ; Trashed packet: nak, retry
  335.         call    pktsize                 ; report packet size
  336.         push    ax
  337.         mov     ah,curchk
  338.         mov     trans.chklen,ah         ; Reset to desired value
  339.         pop     ax
  340.         cmp     flags.cxzflg,0          ; does the user want out now?
  341.         jne     rinit4                  ; ne = yes, quit
  342. rin21a: cmp     ah,'S'                  ; Is it a send initiate packet?
  343.         jne     rinit3                  ; If not see if its an error
  344. rin21:  mov     flags.getflg,0          ; Reset flag
  345.         mov     pack.numtry,0           ; Reset the number of tries
  346.         mov     ax,pack.seqnum  ; Returned packet number. (Synchronize them.)
  347.         inc     ax                      ; Increment it
  348.         and     ax,3FH                  ; Turn off the two high order bits
  349.         mov     pack.pktnum,ax          ; Save modulo 64 of the number
  350.         inc     pack.numpkt             ; Increment the number of packets
  351.         mov     ax,pack.datlen          ; Get the number of arguments received
  352.         mov     bx,offset data          ; Get a pointer to the data
  353.         call    spar                    ; Get data into the proper variables
  354.         mov     bx,offset data          ; Get a pointer to our data block
  355.         call    rpar                    ; Set up the receive parameters
  356.         xchg    ah,al
  357.         mov     ah,0
  358.         mov     pack.datlen,ax          ; Store returned number of arguments
  359.         mov     ah,trans.chklen         ; Checksum length we'll use
  360.         mov     curchk,ah               ; Save it
  361.         mov     trans.chklen,1          ; Use 1 char for init packet
  362.         call    ackpak                  ; acknowledge the packet
  363.         mov     ah,curchk               ; Checksum length we'll use
  364.         mov     trans.chklen,ah         ; Reset to desired value
  365.         mov     pack.state,'F'          ; Set the state to file send
  366.         ret
  367. rin22:  call    nak0                    ; nak the packet
  368.         mov     ah,curchk               ; and only now change checksum from 1
  369.         mov     trans.chklen,ah         ; Reset to desired value
  370.         ret                             ; try again
  371.  
  372. rinit3: cmp     ah,'M'                  ; Message packet?
  373.         jne     rinit3e                 ; ne = no
  374.         call    dodec                   ; decode it
  375.         call    error1                  ; display it
  376.         ret
  377. rinit3e: cmp    ah,'E'                  ; Is it an error packet?
  378.         jne     rinit4                  ; ne = no
  379.         call    error                   ; yes
  380. rinit4: jmp     abort
  381. RINIT   ENDP
  382.  
  383.  
  384. ;       Receive file
  385.  
  386. RFILE   PROC    NEAR
  387.         mov     dl,maxtry
  388.         cmp     pack.numtry,dl  ; Have we reached the maximum number of tries?
  389.         jl      rfile1
  390.         mov     dx,offset ermes8
  391.         jmp     rcverr                  ; do error exit
  392. rfile1: inc     pack.numtry             ; Save the updated number of tries
  393.         call    rpack                   ; Get a packet
  394.          jmp    nak0                    ;  Trashed packet: nak, retry
  395.         call    pktsize                 ; report packet size
  396.         cmp     ah,'S'                  ; Is it a send initiate packet?
  397.         je      rfil10
  398.         cmp     ah,'I'                  ; An Initialization packet?
  399.         je      rfil10                  ; e = yes, don't decode it
  400.         call    dodec                   ; Decode all other incoming packets
  401.         jmp     rfile2                  ;  No, try next type
  402. rfil10: mov     dl,imxtry               ; S and I packets
  403.         cmp     pack.numtry,dl          ; Reached the maximum number of tries?
  404.         jl      rfil12                  ; If not proceed
  405.         mov     dx,offset ermes7
  406.         jmp     rcverr                  ; do error exit
  407. rfil12: mov     ax,pack.pktnum          ; Get the present packet number
  408.         dec     ax                      ; Decrement
  409.         and     ax,3fh                  ; do module 64
  410.         cmp     ax,pack.seqnum  ; Is the packet's number one less than now?
  411.         je      rfil13
  412.         jmp     nak0                    ; No, NAK and try again
  413. rfil13: mov     pack.numtry,0           ; Reset the number of tries
  414.         mov     bx,offset data          ; Get a pointer to our data block
  415.         call    rpar                    ; Set up the parameter information
  416.         xchg    ah,al
  417.         mov     ah,0
  418.         mov     pack.datlen,ax          ; Save the number of arguments
  419.         jmp     ackpak                  ; acknowledge the packet
  420.  
  421. rfile2: cmp     ah,'Z'                  ; Is it an EOF packet?
  422.         jne     rfile3                  ;  No, try next type
  423.         mov     dl,maxtry               ; Z packets
  424.         cmp     pack.numtry,dl  ; Have we reached the maximum number of tries?
  425.         jl      rfil21                  ; If not proceed
  426.         mov     dx,offset ermes9
  427.         jmp     rcverr                  ; do error exit
  428. rfil21: mov     ax,pack.pktnum          ; Get the present packet number
  429.         dec     ax                      ; Decrement
  430.         and     ax,3fh                  ; do modulo 64
  431.         cmp     ax,pack.seqnum  ; Is the packet's number one less than now?
  432.         je      rfil24
  433.         jmp     nak0                    ; No, NAK and try again
  434. rfil24: mov     pack.numtry,0
  435.         mov     pack.datlen,0   ; No data. (The packet number is in seqnum.)
  436.         jmp     ackpak                  ; acknowledge the packet
  437.  
  438. rfile3: cmp     ah,'F'                  ; Start of file (F or X packet)?
  439.         je      rfil31                  ; e = yes
  440.         cmp     ah,'X'                  ; Text header packet?
  441.         jne     rfile4                  ; Neither one.
  442.         mov     flags.xflg,1            ; 'X', say receiving to the screen
  443. rfil31: mov     ax,pack.seqnum          ; Get the packet number
  444.         cmp     ax,pack.pktnum          ; Is it the right packet number?
  445.         je      rfil32
  446.         jmp     nak1                    ; No, NAK it and try again
  447. rfil32: inc     ax                      ; Increment the packet number
  448.         and     ax,3FH                  ; Turn off the two high order bits
  449.         mov     pack.pktnum,ax          ; Save modulo 64 of the number
  450.         inc     pack.numpkt             ; Increment the number of packets
  451.         mov     filopn,0                ; assume not writing to a disk file
  452.         call    dodec                   ; Decode incoming packet for filename
  453.         call    gofil                   ; Get a file to write to
  454.          jmp    abort
  455.         mov     chrcnt,maxpack          ; reset output buffer to be empty
  456.         cmp     flags.xflg,0            ; writing to a disk file?
  457.         jne     rfil32a                 ; ne = no
  458.         mov     filopn,2                ; Disk file open for writing
  459. rfil32a:
  460.         test    flags.remflg,dserial    ; serial display mode?
  461.         jz      rfil33                  ; z = no
  462.         mov     ah,prstr
  463.         mov     dx,offset crlf          ; display cr/lf
  464.         int     dos
  465. rfil33:
  466.         mov     pack.state,'D'          ; Set the state to data receive
  467.         mov     pack.numtry,0           ; Reset the number of tries
  468.         mov     pack.datlen,0   ; No data.  (The packet number is in seqnum.)
  469.         jmp     ackpak                  ; acknowledge the packet
  470.  
  471. rfile4: cmp     ah,'B'                  ; End of transmission?
  472.         jne     rfile5                  ; ne = no
  473.         mov     ax,pack.pktnum
  474.         cmp     ax,pack.seqnum          ; Do we match?
  475.         je      rfil41
  476.         jmp     nak1                    ; No, NAK it and try again
  477. rfil41: mov     pack.state,'C'          ; Set the state to complete
  478.         mov     pack.datlen,0   ; No data.  (Packet number already in seqnum)
  479.         jmp     ackpak                  ; acknowledge the packet
  480.  
  481. rfile5: cmp     ah,'M'                  ; Message packet?
  482.         jne     rfile5e                 ; ne = no
  483.         call    dodec                   ; decode it
  484.         jmp     error1                  ; display it and return
  485.  
  486. rfile5e:cmp     ah,'E'                  ; Is it an error packet?
  487.         jne     rfile6                  ; ne = no
  488.         call    error
  489. rfile6: jmp     abort
  490. RFILE   ENDP
  491.  
  492. ; Get file attributes from packet
  493. ; Recognize file size in bytes and kilobytes (used if bytes missing),
  494. ; file time and date. Reject Mail commands. Return carry clear for success,
  495. ; carry set for failure. If rejecting place reason code in byte temp.
  496. GETATT  PROC    NEAR
  497.         mov     bx,offset data          ; pointer
  498. getat0: push    bx
  499.         sub     bx,offset data
  500.         cmp     bx,pack.datlen          ; are we beyond end of data?
  501.         pop     bx
  502.         jl      getat1                  ; l = not yet
  503.         clc
  504.         ret                             ; has carry clear for success
  505.  
  506. getat1: cmp     byte ptr [bx],'1'       ; byte length field?
  507.         jne     getat2                  ; ne = no
  508.         mov     al,[bx]                 ; remember attribute
  509.         mov     attrib,al
  510.         inc     bx                      ; pointer
  511.         call    getas                   ; get file size
  512.         call    spchk                   ; check available disk space
  513.         jnc     getat0
  514.         ret                             ; return failure
  515.  
  516. getat2: cmp     byte ptr [bx],'!'       ; kilobyte length field?
  517.         jne     getat3                  ; ne = no
  518.         mov     al,[bx]                 ; remember attribute
  519.         mov     attrib,al
  520.         inc     bx                      ; pointer
  521.         call    getak                   ; get file size
  522.         jc      getat5;;;2a                     ; carry means decode rejected
  523.         call    spchk                   ; check available disk space
  524.         jnc     short getat0
  525. getat2a:ret                             ; return failure
  526.  
  527. getat3: cmp     byte ptr [bx],'#'       ; date field?
  528.         jne     getat4                  ; ne = no
  529.         mov     al,[bx]                 ; remember attribute
  530.         mov     attrib,al
  531.         inc     bx
  532.         call    getatd                  ; get file date
  533.         jmp     short getat0
  534.  
  535. getat4: cmp     byte ptr [bx],'+'       ; Disposition?
  536.         jne     getat5                  ; ne = no
  537.         mov     al,[bx]                 ; remember attribute
  538.         mov     attrib,al
  539.         cmp     byte ptr [bx+2],'M'     ; Mail indicator
  540.         jne     getat5                  ; ne = no, ignore field
  541.         stc                             ; set carry for failure
  542.         ret
  543.  
  544. getat5: inc     bx                      ; look at length field
  545.         mov     al,[bx]
  546.         sub     al,' '                  ; remove ascii bias
  547.         mov     ah,0
  548.         inc     ax                      ; include length field byte
  549.         add     bx,ax                   ; skip to next attribute
  550.         jmp     getat0
  551.                                         ; Decode File length (Byte) field
  552. getas:  mov     cl,[bx]                 ; length of file size field
  553.         inc     bx                      ; point at file size data
  554.         sub     cl,' '                  ; remove ascii bias
  555.         mov     ch,0
  556.         mov     ax,0                    ; current length, bytes
  557.         mov     dx,0
  558. getas2: push    cx
  559.         shl     dx,1                    ; high word of size, times two
  560.         mov     di,dx                   ; save
  561.         shl     dx,1
  562.         shl     dx,1                    ; times 8
  563.         add     dx,di                   ; yields dx * 10
  564.         mov     di,dx                   ; save dx
  565.         mov     dx,0
  566.         mov     cx,10                   ; also clears ch
  567.         mul     cx                      ; scale up previous result in ax
  568.         mov     cl,[bx]                 ; get a digit
  569.         inc     bx
  570.         sub     cl,'0'                  ; remove ascii bias
  571.         add     ax,cx                   ; add to current length
  572.         adc     dx,0                    ; extend result to dx
  573.         add     dx,di                   ; plus old high part
  574.         pop     cx
  575.         loop    getas2
  576.         mov     ofilsz+2,ax             ; low order word
  577.         mov     ofilsz,dx               ; high order word
  578.         ret
  579.                                         ; Decode Kilobyte attribute
  580. getak:  mov     ax,ofilsz+2             ; current filesize, low word
  581.         add     ax,ofilsz
  582.         cmp     ax,0                    ; zero if not used yet
  583.         je      getak1                  ; e = not used before
  584.         dec     bx                      ; backup pointer
  585.         stc                             ; set carry to ignore this field
  586.         ret
  587. getak1: call    getas                   ; parse as if Byte field
  588.         mov     ax,ofilsz+2             ; get low word of size
  589.         mov     dx,ofilsz               ; high word
  590.         mov     dh,dl                   ; times 256
  591.         mov     dl,ah
  592.         mov     ah,al
  593.         mov     al,0
  594.         shl     dx,1                    ; times four to make times 1024
  595.         shl     dx,1
  596.         rol     ax,1                    ; two high bits of ah to al
  597.         rol     ax,1
  598.         and     al,3                    ; keep them
  599.         or      dl,al                   ; insert into high word
  600.         mov     al,0
  601.         mov     ofilsz,dx               ; store high word
  602.         mov     ofilsz+2,ax             ; store low word
  603.         clc                             ; clear carry
  604.         ret
  605.  
  606. getatd:                                 ; File date and time
  607.         mov     word ptr ftime,1        ; two seconds past midnight
  608.         mov     word ptr fdate,0
  609.         mov     dl,[bx]                 ; field length
  610.         mov     dh,0
  611.         sub     dl,' '                  ; remove ascii bias
  612.         inc     bx                      ; next field
  613.         add     dx,bx                   ; where next field begins
  614.         mov     temp,dx                 ; save in temp
  615.         mov     ax,0                    ; recover file date and time
  616.         mov     dh,10                   ; multiplier
  617.         cmp     byte ptr[bx+6],' '      ; short form date (yymmdd)?
  618.         je      getad2                  ; e = yes
  619.         add     bx,2                    ; skip century digits (19)
  620. getad2: mov     ax,10
  621.         mov     dx,[bx]                 ; get year tens and units digits
  622.         add     bx,2                    ; dl has tens, dh has units
  623.         sub     dx,'00'                 ; remove ascii bias
  624.         mul     dl                      ; ax = high digit times ten
  625.         add     al,dh                   ; units digit
  626.         sub     ax,80                   ; remove rest of 1980 bias
  627.         jns     getad2a                 ; ns = no sign = non-negative result
  628.         mov     ax,0                    ; don't store less than 1980
  629. getad2a:shl     al,1                    ; adjust for DOS bit format
  630.         mov     fdate+1,al
  631.         mov     ax,[bx]                 ; get month digits
  632.         add     bx,2
  633.         sub     ax,'00'                 ; remove ascii bias
  634.         cmp     al,0                    ; tens digit set?
  635.         je      getad2b                 ; e = no
  636.         add     ah,10                   ; add to units digit
  637. getad2b:cmp     ah,8                    ; high bit of month set?
  638.         jb      getad3                  ; b = no
  639.         or      fdate+1,1
  640.         sub     ah,8                    ; and deduct it here
  641. getad3: mov     cl,5
  642.         shl     ah,cl                   ; normalize months bits
  643.         mov     fdate,ah
  644.         mov     dx,[bx]                 ; do day of the month
  645.         add     bx,2                    ; dh has units, dl has tens digit
  646.         sub     dx,'00'                 ; remove ascii bias
  647.         mov     ax,10
  648.         mul     dl                      ; ax = ten times tens digit
  649.         add     al,dh                   ; plus units digit
  650.         or      fdate,al
  651.         cmp     bx,temp                 ; are we at the end of this field?
  652.         jae     getad5                  ; ae = yes, prematurely
  653.         inc     bx                      ; skip space separator
  654. getad4: mov     ax,10                   ; prepare for hours
  655.         mov     dx,[bx]                 ; hh digits
  656.         add     bx,2
  657.         sub     dx,'00'                 ; remove ascii bias
  658.         mul     dl                      ; 10*high digit of hours
  659.         add     al,dh                   ; plus low digit of hours
  660.         mov     cl,3                    ; normalize bits
  661.         shl     al,cl
  662.         mov     ftime+1,al              ; store hours
  663.         inc     bx                      ; skip colon
  664.         mov     ax,10                   ; prepare for minutes
  665.         mov     dx,[bx]                 ; mm digits
  666.         add     bx,2
  667.         sub     dx,'00'                 ; remove ascii bias
  668.         mul     dl                      ; 10*high digit of minutes
  669.         add     al,dh                   ; plus low digit of minutes
  670.         mov     ah,0
  671.         mov     cl,5                    ; normalize bits
  672.         shl     ax,cl
  673.         or      ftime+1,ah              ; high part of minutes
  674.         mov     ftime,al                ; low part of minutes
  675.         cmp     bx,temp                 ; are we at the end of this field
  676.         jae     getad5                  ; ae = yes, quit here
  677.         inc     bx                      ; skip colon
  678.         mov     ax,10                   ; prepare for seconds
  679.         mov     dx,[bx]                 ; ss digits
  680.         add     bx,2
  681.         sub     dx,'00'                 ; remove ascii bias
  682.         mul     dl                      ; 10*high digit of seconds
  683.         add     al,dh                   ; plus low digit of seconds
  684.         shr     al,1                    ; store as double-seconds for DOS
  685.         or      ftime,al                ; store seconds
  686. getad5: ret
  687. GETATT  ENDP
  688.  
  689. ; Receive data
  690.  
  691. RDATA   PROC    NEAR
  692.         mov     dl,maxtry
  693.         cmp     pack.numtry,dl          ; Get the number of tries
  694.         jl      rdata1
  695.         mov     dx,offset erms10
  696.         jmp     rcverr                  ; do error exit
  697. rdata1: inc     pack.numtry             ; Save the updated number of tries
  698.         call    rpack                   ; Get a packet
  699.          jmp    nak0                    ;  Trashed packet: nak, retry
  700.          nop
  701.         call    pktsize                 ; report packet size
  702.         cmp     ah,'D'                  ; Is it a data packet?
  703.         je      rdat11                  ; e = yes
  704.         cmp     ah,'A'                  ; Attributes packet?
  705.         jne     rdata7                  ; ne = no
  706.         mov     ax,pack.pktnum
  707.         cmp     ax,pack.seqnum          ; Do we match?
  708.         je      rdata6
  709.         jmp     nak1                    ; No, NAK it and try again
  710. rdata6: call    getatt                  ; get file attributes from packet
  711.         mov     pack.numtry,0           ; Reset number of tries
  712.         jnc     rdata6a                 ; nc = success
  713.         mov     pack.datlen,2   ; 2 bytes (Packet number already in seqnum)
  714.         mov     data,'N'                ; Decline the transfer
  715.         mov     al,attrib               ; get attribute causing rejection
  716.         mov     data+1,al               ; report rejection reason to sender
  717.         or      fsta.xstatus,2          ; set status, failed
  718.         mov     kstatus,2               ; global status
  719.         jmp     short rdata6b
  720. rdata6a:mov     pack.datlen,0   ; No data. (Packet number already in seqnum)
  721. rdata6b:mov     ax,pack.pktnum
  722.         inc     ax                      ; Increment the packet number
  723.         and     ax,3FH                  ; Turn off the two high order bits
  724.         mov     pack.pktnum,ax          ; Save modulo 64 of the number
  725.         inc     pack.numpkt             ; Increment the number of packets
  726.         jmp     ackpak                  ; acknowledge the packet
  727.  
  728. rdata7: call    dodec                   ; Decode data
  729.         jmp     rdata2                  ; try next type
  730.                                         ; D packets
  731. rdat11: mov     ax,pack.pktnum          ; Get the present packet number
  732.         cmp     ax,pack.seqnum          ; Is the packet's number correct?
  733.         jz      rdat14
  734.         mov     dl,maxtry
  735.         cmp     pack.numtry,dl  ; Have we reached the maximum number of tries?
  736.         jl      rdat12                  ; If not proceed
  737.         mov     dx,offset erms10
  738.         jmp     rcverr                  ; do error exit
  739. rdat12: mov     ax,pack.pktnum
  740.         dec     ax
  741.         and     ax,3fh                  ; do modulo 64
  742.         cmp     ax,pack.seqnum  ; Is the packet's number one less than now?
  743.         je      rdat13
  744.         jmp     nak0                    ; No, NAK it and try again
  745. rdat13: mov     pack.numtry,0           ; Reset number of tries
  746.         mov     pack.datlen,0   ; No data.  (The packet number is in seqnum.)
  747.         jmp     ackpak                  ; acknowledge the packet
  748.  
  749. rdat14: inc     pack.pktnum             ; Increment the packet number
  750.         and     pack.pktnum,3fh         ; Save modulo 64 of the number
  751.         inc     pack.numpkt             ; Increment the number of packets
  752.         mov     ax,pack.datlen          ; Get the length of the data
  753.         cmp     flags.cxzflg,0          ; Has the user typed a ^X or ^Z?
  754.         je      rdt14x                  ; No, write out the data
  755.         or      fsta.xstatus,2+80h      ; set status, failed + intervention
  756.         mov     kstatus,2+80h           ; global status
  757.         cmp     flags.abfflg,1          ; Discard incomplete files?
  758.         je      rdat15          ; If yes don't write data out to file
  759. rdt14x: call    ptchr                   ; decode the data and output to file
  760.          jmp    abort                   ;  Unable to write out chars; abort
  761. rdat15: mov     pack.numtry,0           ; Reset the number of tries
  762.         mov     pack.datlen,0   ; No data.  (Packet number still in seqnum.)
  763.         cmp     flags.cxzflg,0          ; Interrupt file transfer?
  764.         je      rdat16                  ; Nope
  765.         or      fsta.xstatus,2+80h      ; set status, failed + intervention
  766.         mov     kstatus,2+80h           ; global status
  767.         mov     bx,offset data          ; Send data in ACK in case remote
  768.         mov     ah,flags.cxzflg         ;  knows about ^X/^Z
  769.         mov     [bx],ah                 ; Put data into the packet
  770.         mov     pack.datlen,1           ; Set data size to 1
  771.         mov     cx,1
  772.         call    doenc
  773. rdat16: jmp     ackpak                  ; acknowledge the packet
  774.  
  775. rdata2: cmp     ah,'F'                  ; Start of file?
  776.         je      rdat20                  ; e = yes
  777.         cmp     ah,'X'                  ; Text header packet?
  778.         jne     rdata3                  ;  No, try next type
  779. rdat20: mov     dl,maxtry               ; F or X packet
  780.         cmp     pack.numtry,dl          ; Reached the max number of tries?
  781.         jl      rdat21                  ; If not proceed
  782.         mov     dx,offset ermes8
  783.         jmp     rcverr                  ; do error exit
  784. rdat21: mov     ax,pack.pktnum
  785.         dec     ax
  786.         and     ax,3fh                  ; modulo 64
  787.         cmp     ax,pack.seqnum  ; Is the packet's number one less than now?
  788.         je      rdat22
  789.         jmp     nak0                    ; No, NAK it and try again
  790. rdat22: mov     pack.numtry,0           ; Reset number of tries
  791.         mov     pack.datlen,0   ; No data.  (The packet number is in seqnum.)
  792.         jmp     ackpak                  ; acknowledge the packet
  793.  
  794. rdata3: cmp     ah,'Z'                  ; Is it a EOF packet?
  795.         je      rdat3x                  ; e = yes
  796.         jmp     rdata4                  ; Try and see if its an error
  797. rdat3x: mov     ax,pack.pktnum          ; Get the present packet number
  798.         cmp     ax,pack.seqnum          ; Is the packet's number correct?
  799.         je      rdat32
  800.         jmp     nak0                    ; No, NAK it and try again
  801. rdat32: inc     ax                      ; Increment the packet number
  802.         and     ax,3FH                  ; Turn off the two high order bits
  803.         mov     pack.pktnum,ax          ; Save modulo 64 of the number
  804.         inc     pack.numpkt
  805.         call    dodec                   ; Decode incoming packet
  806.         cmp     flags.cxzflg,0          ; Do we want to discard the file?
  807.         jne     rdt32x                  ; ne = yes
  808.         cmp     fmtdsp,0                ; formatted screen?
  809.         je      rdat32a                 ; e = no, no message
  810.         mov     ax,ofilsz               ; high word of attributes file size
  811.         or      ax,ofilsz+2             ; low word
  812.         cmp     ax,0                    ; was file size given by other side?
  813.         je      rdat32a                 ; e = no
  814.         call    perpos                  ; position cursor to percent done
  815.         mov     dx,offset donemsg       ; say 100%
  816.         mov     ah,prstr
  817.         int     dos
  818. rdat32a:cmp     pack.datlen,1           ; One piece of data?
  819.         jne     rdat33                  ; Nope - finish writing out file?
  820.         cmp     data,'D'                ; is the data "D" for discard?
  821.         jne     rdat33                  ; Nope - write out file
  822. rdt32x: cmp     flags.abfflg,0          ; Keep incomplete files?
  823.         je      rdat33                  ; Yes, go write it out
  824.         cmp     flags.xflg,1            ; Writing to the screen?
  825.         je      rdt32y                  ; Don't close "file"
  826.         cmp     flags.destflg,2         ; file destination = screen?
  827.         je      rdt32y                  ; e = yes, no file to close
  828.         push    bx
  829.         mov     ah,close2               ; DOS 2.0 file close
  830.         mov     bx,diskio.handle        ; file handle
  831.         int     dos                     ; Kill it, ignore errors
  832.         pop     bx
  833.         mov     filopn,0                ; File closed now
  834.         mov     dx,offset diskio.string ; get the filename
  835.         mov     ah,del2                 ; DOS 2.0 file delete
  836.         int     dos
  837. rdt32y: cmp     flags.cxzflg,'X'        ; Kill one file or all?
  838.         je      rdt32ya                 ; e = one (^X)
  839.         jmp     rdat36                  ; No so leave flag alone
  840. rdt32ya:call    cxmsg                   ; Clear msg about interrupt
  841.         or      errlev,2                ; set DOS error level
  842.         or      fsta.xstatus,2+80h      ; set status, failed + intervention
  843.         mov     kstatus,2+80h           ; global status
  844.         test    flags.remflg,dquiet     ; quiet display?
  845.         jnz     rdt32z                  ; nz = yes
  846.         cmp     flags.destflg,2         ; Receiving to the screen?
  847.         je      rdt32z                  ; e = yes, no formatted display
  848.         call    intmsg
  849. rdt32z: mov     flags.cxzflg,0          ; Reset - ^X only kills one file
  850.         jmp     rdat36
  851. rdat33: cmp     flags.eofcz,0           ; should we write a ^Z?
  852.         jz      rdat35                  ; no, keep going
  853.         cmp     flags.xflg,0            ; writing to a file?
  854.         jne     rdat35                  ; no, skip ^Z
  855. rdt33x: cmp     chrcnt,0                ; any space left in output buffer?
  856.         jg      rdat34                  ; g = yes
  857.         call    outbuf                  ; Write out buffer if no room for ^Z
  858.          jmp    abort
  859. rdat34: mov     cl,'Z'- 40h             ; Put in a ^Z for EOF
  860.         push    bx
  861.         mov     bx,bufpnt               ; Get the dma pointer
  862.         mov     [bx],cl                 ; Add it
  863.         pop     bx
  864.         dec     chrcnt
  865. rdat35: call    outbuf                  ; Output the last buffer
  866.          jmp    abort                   ; Give up if the disk is full
  867.         cmp     flags.xflg,1            ; Writing to the screen?
  868.         je      rdat37                  ; Yes, don't close "file"
  869.         cmp     flags.destflg,2         ; file destination = screen?
  870.         je      rdat37                  ; e = yes, no file to close
  871.         push    bx                      ; do file attributes and close
  872.         mov     cx,word ptr ftime       ; new time
  873.         mov     dx,word ptr fdate       ; new date
  874.         mov     word ptr fdate,0
  875.         mov     word ptr ftime,0        ; clear current time/date attributes
  876.         mov     ax,cx
  877.         or      ax,dx
  878.         jz      rdat35b                 ; z = no attributes to set
  879.         cmp     cx,0                    ; time set as null?
  880.         jne     rdat35a                 ; ne = no
  881.         inc     cl                      ; two seconds past midnight
  882. rdat35a:mov     ah,setattr              ; set file date/time attributes
  883.         mov     al,1                    ; set, not get
  884.         mov     bx,diskio.handle        ; file handle
  885.         int     dos                     ; end of file attributes
  886. rdat35b:mov     ah,close2               ; DOS 2.0 file close
  887.         mov     bx,diskio.handle        ; file handle
  888.         int     dos
  889.         pop     bx
  890.         mov     filopn,0                ; File closed now
  891. rdat36: cmp     flags.destflg,0         ; Writing to printer?
  892.         jne     rdat37                  ; ne = no, skip next part
  893.         cmp     flags.xflg,1            ; Writing to screen?
  894.         je      rdat37                  ; Yes, skip this part
  895.         mov     dl,ff                   ; Send a form feed
  896.         mov     ah,lstout               ; Write out to first printer
  897.         int     dos
  898. rdat37: mov     pack.numtry,0           ; Reset the number of tries
  899.         mov     pack.datlen,0   ; No data.  (The packet number is in seqnum.)
  900.         call    ackpak                  ; acknowledge the packet
  901.         mov     pack.state,'F'
  902.         mov     ax,0            ; tell statistics this was a receive operation
  903.         call    endtim                  ; get tod & size of file transfer
  904.         ret
  905. rdata4: cmp     ah,'M'                  ; Message packet?
  906.         jne     rdata4e                 ; ne = no
  907.         call    dodec                   ; decode it
  908.         jmp     error1                  ; display it and return
  909.  
  910. rdata4e: cmp    ah,'E'                  ; Is it an error packet?
  911.         jne     rdata5                  ; ne = no
  912.         call    error
  913. rdata5: jmp     abort
  914. RDATA   ENDP
  915.  
  916. ; Error exit. Enter with dx pointing to error message. [jrd]
  917. rcverr  proc    near
  918.         test    flags.remflg,dquiet     ; quiet display mode?
  919.         jnz     rcver1                  ; nz = yes. Don't write to screen
  920.         cmp     flags.destflg,2         ; Receiving to the screen?
  921.         je      rcver1                  ; e = yes, no formatted display
  922.         call    erpos                   ; Position cursor
  923.         mov     ah,prstr
  924.         int     dos                     ; Print an error message
  925. rcver1: mov     bx,dx                   ; set bx to error message
  926.         call    errpack                 ; Send error packet just in case
  927.         jmp     abort                   ; Change the state to abort
  928. rcverr  endp
  929.  
  930. ; Called by GETATT in receiver code to verify sufficient disk space.
  931. ; Gets file path from diskio.string setup in mssfil, remote size in ofilsz
  932. ; from getatt, and whether a disk file or not via ioctl on the file handle.
  933. ; Returns carry clear if enough space.
  934. spchk   proc    near                    ; check for enough disk space
  935.         push    ax
  936.         push    bx
  937.         push    cx
  938.         push    dx
  939.         mov     ah,ioctl                ; ask DOS about this file handle
  940.         mov     al,0                    ; get info
  941.         mov     bx,diskio.handle
  942.         int     dos
  943.         test    dl,80h                  ; handle is a disk file?
  944.         jnz     spchk5b                 ; nz = no, always enough space
  945.         inc     dl
  946.         and     dl,01fh                 ; get current drive from bits 5-0
  947.         mov     ah,36h                  ; get disk free space
  948.         int     dos
  949.         cmp     ax,0ffffh               ; error response?
  950.         je      spchk6                  ; e = yes
  951.         mul     bx                      ; sectors/cluster * clusters = sectors
  952.         mov     bx,dx                   ; save high word of sectors (> 64K)
  953.         mul     cx                      ; bytes = sectors * bytes/sector
  954.         push    ax                      ; save low word of bytes
  955.         mov     ax,bx                   ; recall sectors high word
  956.         mov     bx,dx                   ; save current bytes high word
  957.         mul     cx                      ; high word sectors * bytes/sector
  958.         add     ax,bx                   ; new high bytes + old high bytes
  959.         push    ax                      ; save high word, dx:ax
  960.         mov     dx,ofilsz               ; high word of file size dx:ax
  961.         mov     ax,ofilsz+2             ; low word
  962.         mov     cx,dx                   ; copy size long word to cx:bx
  963.         mov     bx,ax
  964.         shr     bx,1                    ; divide long word by two
  965.         shr     cx,1
  966.         jnc     spchk2                  ; nc = no carry down
  967.         or      bx,8000h                ; get carry down
  968. spchk2: shr     bx,1                    ; divide by two again
  969.         shr     cx,1
  970.         jnc     spchk3
  971.         or      bx,8000h                ; get carry down
  972. spchk3: shr     bx,1                    ; divide long word by two
  973.         shr     cx,1
  974.         jnc     spchk4                  ; nc = no carry down
  975.         or      bx,8000h                ; get carry down
  976. spchk4: shr     bx,1                    ; divide long word by two
  977.         shr     cx,1
  978.         jnc     spchk5                  ; nc = no carry down
  979.         or      bx,8000h                ; get carry down
  980. spchk5: add     ax,bx                   ; form dx:ax = (17/16) * dx:ax
  981.         adc     dx,cx
  982. spchk5a:pop     cx                      ; high word of disk space
  983.         pop     bx                      ; low word
  984.         sub     bx,ax                   ; minus inflated file size, low word
  985.         sbb     cx,dx                   ;  and high word
  986.         js      spchk6                  ; s = not enough space for file
  987. spchk5b:clc
  988.         jmp     short spchk7            ; enough space
  989. spchk6: call    erpos                   ; Position cursor
  990.         mov     ah,prstr
  991.         mov     dx,offset erms11        ; Not enough space for file
  992.         int     dos
  993.         stc
  994. spchk7: pop     dx
  995.         pop     cx
  996.         pop     bx
  997.         pop     ax
  998.         ret
  999. spchk   endp
  1000.  
  1001.  
  1002. ; Jumping to this location is like retskp.  It assumes the instruction
  1003. ;   after the call is a jmp addr
  1004.  
  1005. RSKP    PROC    NEAR
  1006.         pop     bp
  1007.         add     bp,3
  1008.         push    bp
  1009.         ret
  1010. RSKP    ENDP
  1011.  
  1012. code    ends
  1013.         end
  1014.  
  1015.  
  1016.